﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace OffLineFilter
{
    public class DictionaryIncorrectColumnCountException : Exception
    {
        public DictionaryIncorrectColumnCountException() : 
            base("Некорректное количество столбцов в одной из строк словаря.") 
        { }
    }
    public class DictionaryNumberParseFailureException : Exception
    {
        public DictionaryNumberParseFailureException() :
            base("Невозможно преобразовать в число столбец одной из строк словаря.")
        { }
    }
    public class DictionaryItemAlreadyExistsException : Exception
    {
        public DictionaryItemAlreadyExistsException() :
            base("Невозможно добавить запись в словарь. Словарь уже содержит такую лемму.")
        { }
    }

    public class Dictionary
    {
        public class NumericPair
        {
            public int WordCount { get; set; }
            public double IdfValue { get; set; }

            public NumericPair(int wordCount, double idfValue)
            {
                WordCount = wordCount;
                IdfValue = idfValue;
            }
        }

        protected readonly int columns = 3;
        protected readonly char[] separators = new[] { ';' };
        protected Dictionary<string, NumericPair> dictionary;

        public string LastException { get; set; }
        public string FileName { get; set; }
        public int Count 
        {
            get
            {
                if (dictionary == null)
                    return 0;

                return dictionary.Count;
            }
        }
        public double MaxIdf
        {
            get
            {
                return dictionary
                    .Select(pair => pair.Value.IdfValue)
                    .Max();
            }
        }
        public double LengthMb { get; set; }
        
        public Dictionary(string fileName)
        {
            FileName = fileName;
        }

        public NumericPair this[string key]
        {
            get
            {
                if (dictionary == null)
                    return null;

                if (!dictionary.ContainsKey(key))
                    return null;

                return dictionary[key];
            }
            set
            {
                if (dictionary == null)
                    return;

                if (dictionary.ContainsKey(key))
                    return;

                dictionary.Add(key, value);
            }
        }

        private bool LoadAllowed()
        {
            if (String.IsNullOrEmpty(FileName))
                return false;

            if (!File.Exists(FileName))
                return false;

            return true;
        }

        private bool ReadLines()
        {
            if (dictionary == null)
                dictionary = new Dictionary<string, NumericPair>();
            else
                dictionary.Clear();

            string line, key;
            int count;
            double idf;

            try
            {
                using (StreamReader stream = new StreamReader(FileName, Encoding.Default))
                {
                    while ((line = stream.ReadLine()) != null)
                    {
                        ParseLine(line, out key, out count, out idf);
                        dictionary.Add(key, new NumericPair(count, idf));
                    }
                }
            }
            catch (Exception e)
            {
                LastException = e.Message;
                return false;
            }

            return true;
        }

        private bool GetLengthMb()
        {
            try
            {
                FileInfo fileInfo = new FileInfo(FileName);
                LengthMb = fileInfo.Length / Math.Pow(2, 20);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public bool Load()
        {
            if (!LoadAllowed())
                return false;

            GetLengthMb();

            if (!ReadLines())
                return false;

            return true;
        }

        private void ParseLine(String line, out string key, out int count, out double idf)
        {
            string[] columnsArr = line.Split(separators, StringSplitOptions.RemoveEmptyEntries);
            if (columnsArr.Length != columns)
                throw new DictionaryIncorrectColumnCountException();

            key = columnsArr[0];
            if (!int.TryParse(columnsArr[1], out count) || !double.TryParse(columnsArr[2], out idf))
                throw new DictionaryNumberParseFailureException();

            if (dictionary.ContainsKey(key))
                throw new DictionaryItemAlreadyExistsException();
        }
    }
}
